<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      // 1. 什么是作用域。作用域链
      /**
       * 1. 变量可以访问的范围，称之为作用域
       * 2. 前端开发中作用域主要有如下几类：
       *    全局，函数，块级，模块（单独的.js文件 外部默认是无法访问内部的变量的，除非导出）
       * 3. 当我们在访问变量的时候，遵循就近原则：
       *  当前作用域有，就用
       *  没有呢，就去上一级作用域找，找到全局作用域为止
       * 4. 还找不到，就报错
       * 5. 刚刚检索作用域的这个路线，称之为 作用域链
       * 6. 正是因为有作用域链，我们才可以访问 外部作用域的变量
       * */
      // 全局作用域中
      const info = '123'
      function sayHi() {
        // 函数作用域
        let message = '你好吗'
        if (true) {
          // 块级作用域
          let food = '剁椒鱼头'
          // 使用变量的时候回遵循就近原则
          // console.log(food)
          // console.log(message)
          // console.log(info)
          // console.log(chicken)
        }
      }
      sayHi()

      // 2. this指向问题（笔试题）
      /**
       * 1. this 比较灵活，较为常见的判断方法是，谁调用，就是谁
       * 2. 如果看不出来是谁调用，可能是 window
       * 3.我们可以人为的指定 this 指向，通过 call，apply。bind
       *  call，apply 调用函数并传入具体的 this
       *  bind，返回一个绑定了 this 的新函数
       * 4. 但是现在这 3 个方法都【用的不多】，因为可以用箭头函数来绑定 this，箭头函数中的 this 创建时所在作用域中的 this
       * https://www.bilibili.com/video/BV1mH4y1Q7Z7/?spm_id_from=333.999.0.0&vd_source=01f374720bfabb6b6d33c9e1ffaf0a26
       * */
      const person = {
        name: 'jack',
        sayHi() {
          console.log(this) // ?
          // setTimeout(function () {
          //   console.log(this) // ?
          // }, 1000)
          setTimeout(() => {
            console.log(this) // ?
          }, 1000)
        },
      }
      // person.sayHi()

      // 3. 什么是原型，什么是原型链。
      /**
       * 1. js设计之初为了实现面向对象，有了一个叫做原型的属性（概念）
       * 2. 添加在原型上的属性，方法，所有实例化对象都可以共享
       * 3. 可以利用这个特性来共享一些属性和方法
       * 4. 对象 有原型，原型他也是一个对象
       * 5. 既然原型也是对象，他也有自己的原型
       * 6. 当我们在使用某些属性和方法的时候会顺着原型的这个关系，依次逐级往上找，这个查找的关系叫做原型链
       * 7.原型链的顶端 是 Object 的原型，在往上就没有了
       * */
      // 构造函数
      function Dog() {}
      // 原型加给构造函数的
      Dog.prototype.bark = function () {
        console.log('喵喵喵~~')
      }
      const d1 = new Dog()
      const d2 = new Dog()
      // console.log(d1 === d2)
      // d1.bark()
      // d2.bark()
      console.log(d2.toString())
      console.log(d2.valueOf())
      // console.log(d2.memeda())

      // 实例化对象的原型，可以通过 __proto__来访问

      // 4. prototype和__proto__之间有什么区别。
      /**
       * 1. prototype 是通过构造函数点出来的，修改之后所有实例化的对象都可以访问
       * 2.__proto__ 是通过实例化对象点出来的，指向的也是 prototype
       * 3.但是非常不建议通过 __proto__去修改原型对象，因为访问速度缓慢，只是出于兼容的考虑保留了这个属性（mdn 说的）
       */
      // 构造函数
      function Cat() {}
      Cat.prototype.info = function () {
        console.log('我是一只喵~')
      }
      // 实例化对象
      const c1 = new Cat()
      // 5. 什么是闭包。比较常见的场景。
      /**
       * 1. 闭包是由捆绑起来（封闭的）的函数和函数周围状态（词法环境）的引用组合而成。换言之，闭包让函数能访问它的外部作用域。在 JavaScript 中，闭包会随着函数的创建而同时创建。
       * 2. 翻译一下：闭包指的是函数及他所在的所用于组合起来的环境
       * 3. 作用：
       *  可以通过函数间接访问，函数所在作用域中的变量
       *  起到一定的封装作用,只能使用提供的功能去讲解操纵内部的变量
       * 4.缺点：变量没有被及时回收，可能会造成内存泄露，解决方法是，导出的函数不用了就设置为 null
       *
       */

      function outter() {
        let food = '隆江猪脚饭'
        let food2 = '仙庙烧鸭'

        function innter() {
          console.log(food)
          console.log(food2)
        }
        function innter2(nF, nF2) {
          food = nF
          food2 = nF2
        }

        // return innter
        return innter2
      }

      const func = outter()

      func()

      // 全局作用域没有，报错了
      // console.log(food)
      // console.log(food2)
    </script>
  </body>
</html>
